'use strict';

(function () {
  //Setup map events from a google map object to trigger on a given element too,
  //then we just use ui-event to catch events from an element
  function bindMapEvents(scope, eventsStr, googleObject, element) {
    angular.forEach(eventsStr.split(' '), function (eventName) {
    	//Prefix all googlemap events with 'map-', so eg 'click'
    	//for the googlemap doesn't interfere with a normal 'click' event
    	var _eventName = eventName;
    	if(_eventName == 'complete'){
    		_eventName = 'tilesloaded';
    	}
    	window.google.maps.event.addListener(googleObject, _eventName, function (event) {
        	element.triggerHandler('map-' + eventName, event);
	        //We create an $apply if it isn't happening. we need better support for this
	        //We don't want to use timeout because tons of these events fire at once,
	        //and we only need one $apply
	        if (!scope.$$phase){ scope.$apply();}
	    });
    });
  }

  app.value('uiMapConfig', {
		disableDefaultUI: true,
	    keyboardShortcuts: false,
	    disableDoubleClickZoom: true,
	    clickableIcons:false,
	    scrollwheel: true, //鼠标滚动放大
	    streetViewControl: false,
	    center: {lat: 30.473786, lng: 114.405978},
	    maxZoom: 18,
	    minZoom: 5
	});
  app.directive('uiMap',
    ['uiMapConfig', '$parse', function (uiMapConfig, $parse) {

      var mapEvents = 'bounds_changed center_changed click dblclick drag dragend ' +
        'dragstart heading_changed idle maptypeid_changed mousemove mouseout ' +
        'mouseover projection_changed resize rightclick tilesloaded tilt_changed ' +
        'zoom_changed';
      var options = uiMapConfig || {};

      return {
        restrict: 'A',
        //doesn't work as E for unknown reason
        link: function (scope, elm, attrs) {
	          var opts = angular.extend({}, options, scope.$eval(attrs.uiOptions));
	          if(opts.mapTypeId == null){
	          	opts.mapTypeId = window.google.maps.MapTypeId.TERRAIN;
	          }
	          var map = new window.google.maps.Map(elm[0], opts);
	          var model = $parse(attrs.uiMap);
	
	          map.getCurrentMapPos_ = function(){
	        	var pos = {};
	            var bounds = this.getBounds();   //获取可视区域
	            if(bounds == null){
	            	var center = this.map.getCenter();
					if(center != null){
			        	pos = {
		                    "x1": center.lng(),
		                    "y1": center.lat(),
		                    "x2": center.lng(),
		                    "y2": center.lat()
		                }
					}
	            }else{
		            var ne = bounds.getNorthEast(); //可视区域右上角
		            var sw = bounds.getSouthWest(); //可视区域左下角
		            pos = {
	                    "x1": sw.lng(),
	                    "y1": sw.lat(),
	                    "x2": ne.lng(),
	                    "y2": ne.lat()
	                }
	            }
	            return pos;
	        }
	        map.getMapCenter_ = function(){
            	var center = this.map.getCenter();
            	return {
            		"lng": center.lng(),
                    "lat": center.lat(),
            	}
            }
	        //设置地图中心
	        map.setMapCenter_ = function(lat, lng){
	        	this.setCenter(new google.maps.LatLng(lat, lng));
	        }
	        map.newMapIcon_ = function(iconUrl, width, height){
	        	var icon = {
					url: iconUrl,
					// 设置坐标为图片中心
					anchor: new google.maps.Point(width, height)
				};
		        return icon;
	        }
	        map.newMapMarker_ = function(lat, lng, image, draggable_, bemsObj_){
				var marker = new google.maps.Marker({
					map: this,
					position: new google.maps.LatLng(lat, lng),
					icon: image,
					draggable:draggable_,
					bemsObj: bemsObj_
				});
				marker.getPosition_ = function(){
					return this.getPosition();
				}
	        	return marker;
	        }
            
	        //Set scope variable for the map
	        model.assign(scope, map);
	
	        bindMapEvents(scope, mapEvents, map, elm);
        }
      };
  }]);

  app.value('uiMapInfoWindowConfig', {});
  
  //Map Infor Window Controller
  app.controller('uiMapInfoWindowCtrl', 
  	['$scope','$element', '$attrs', '$exceptionHandler','uiMapInfoWindowConfig', '$parse', '$compile',
  	function(scope, elm, attrs,$exceptionHandler,uiMapInfoWindowConfig, $parse, $compile){
	    var ctrl = this;
  		
  		var infoWindowEvents = 'closeclick content_change domready ' +
	        'position_changed zindex_changed';
	        
	    var options = uiMapInfoWindowConfig || {};
	    
	    ctrl.init = function(){
			  var opts = angular.extend({}, options, scope.$eval(attrs.uiOptions));
	          opts.content = elm[0];
	          var model = $parse(attrs.uiMapInfoWindow);
	          var infoWindow = model(scope);
	
	          if (!infoWindow) {
	          	//不存在时先定位
	          	if(!window.USGSOverlay){
	          		difineInfoWindow();
	          	}
	            infoWindow = new USGSOverlay(elm[0]);
	            //infoWindow = new window.google.maps.InfoWindow(opts);
	            model.assign(scope, infoWindow);
	          }
	
	          bindMapEvents(scope, infoWindowEvents, infoWindow, elm);
	
	          /* The info window's contents dont' need to be on the dom anymore,
	           google maps has them stored.  So we just replace the infowindow element
	           with an empty div. (we don't just straight remove it from the dom because
	           straight removing things from the dom can mess up angular) */
	          elm.replaceWith('<div></div>');
	
	          //Decorate infoWindow.open to $compile contents before opening
	          var _open = infoWindow.open;
	          var _isInited = false;
	          infoWindow.open = function open(a1, a2, a3, a4, a5, a6) {
	            if(!_isInited){
	                $compile(elm.contents())(scope);
	                _isInited = true;
	            }
	            _open.call(infoWindow, a1, a2, a3, a4, a5, a6);
	          };
		}
  }]);
  //自定义Info Window Controller
  app.controller('CustomerInfoWindowCtrl', 
  	['$scope','$element', '$attrs', '$exceptionHandler','uiMapInfoWindowConfig', '$parse', '$compile','$timeout','$document',
  	function(scope, elm, attrs,$exceptionHandler,uiMapInfoWindowConfig, $parse, $compile, $timeout, $document){
	    var ctrl = this;
  		
  		var infoWindowEvents = 'closeclick content_change domready ' +
	        'position_changed zindex_changed';
	        
	    var options = uiMapInfoWindowConfig || {};
	    
	    ctrl.init = function(){
	    	
			  var opts = angular.extend({}, options, scope.$eval(attrs.uiOptions));
			  
	          var model = $parse(attrs.uiMapInfoWindowCus);
	          var infoWindow = model(scope);
	
	          if (!infoWindow) {
	            infoWindow = {};
	            model.assign(scope, infoWindow);
	          }
	
	          var _isInited = false;
	          infoWindow.open = function (a1, a2, a3, a4, a5, a6) {
	            if(!_isInited){
	                //$compile(elm.contents())(scope);
	                _isInited = true;
	            }
	            $timeout(function(){
		            elm.triggerHandler('dialog-open');
		            elm.show();
	            }, 100)
	          };
	          infoWindow.close = function(){
	          	elm.hide(100);
	          }
	          //设置绝对定位并隐藏最下方的箭头
	          elm.css({position: 'absolute', display:'none', 'zIndex': 1026}).find('.arrow-bottom').hide();
		}
  }]);
  app.directive('uiMapInfoWindow',
    ['uiMapInfoWindowConfig', '$parse', '$compile', function (uiMapInfoWindowConfig, $parse, $compile) {
      return {
      	controller: 'uiMapInfoWindowCtrl',//uiMapInfoWindowCtrl
        link: function (scope, elm, attrs, ctrls) {
          ctrls.init();
        }
      };
    }]);
  app.directive('uiMapInfoWindowCus',
    ['$parse', '$compile', function ( $parse, $compile) {
      return {
      	controller: 'CustomerInfoWindowCtrl',//uiMapInfoWindowCtrl
        link: function (scope, elm, attrs, ctrls) {
          ctrls.init();
        }
      };
    }]);

  /*
   * Map overlay directives all work the same. Take map marker for example
   * <ui-map-marker="myMarker"> will $watch 'myMarker' and each time it changes,
   * it will hook up myMarker's events to the directive dom element.  Then
   * ui-event will be able to catch all of myMarker's events. Super simple.
   */
  function mapOverlayDirective(directiveName, events) {
    app.directive(directiveName, [function () {
      return {
        restrict: 'A',
        link: function (scope, elm, attrs) {
          scope.$watch(attrs[directiveName], function (newObject) {
            if (newObject) {
              bindMapEvents(scope, events, newObject, elm);
            }
          });
        }
      };
    }]);
  }

  mapOverlayDirective('uiMapMarker',
    'animation_changed click clickable_changed cursor_changed ' +
      'dblclick drag dragend draggable_changed dragstart flat_changed icon_changed ' +
      'mousedown mouseout mouseover mouseup position_changed rightclick ' +
      'shadow_changed shape_changed title_changed visible_changed zindex_changed');

  mapOverlayDirective('uiMapPolyline',
    'click dblclick mousedown mousemove mouseout mouseover mouseup rightclick');

  mapOverlayDirective('uiMapPolygon',
    'click dblclick mousedown mousemove mouseout mouseover mouseup rightclick');

  mapOverlayDirective('uiMapRectangle',
    'bounds_changed click dblclick mousedown mousemove mouseout mouseover ' +
      'mouseup rightclick');

  mapOverlayDirective('uiMapCircle',
    'center_changed click dblclick mousedown mousemove ' +
      'mouseout mouseover mouseup radius_changed rightclick');

  mapOverlayDirective('uiMapGroundOverlay',
    'click dblclick');
    
  //选择模式指令
  app.directive('uiMapSelectMode', ['$parse', function ($parse) {
      return {
        restrict: 'A',
        link: function (scope, elm, attrs) {
        	var model = $parse(attrs.uiMapSelectMode);
        	//地图选择模式回调函数
        	var selectedFun = scope.$eval(attrs.uiMapSelectedFun);
          	var rectangle = model(scope);
          	// 选择框为null时初始化选择框
          	if (!rectangle) {
	          	rectangle = new google.maps.Rectangle({
				    strokeColor: '#FF0000',
				    strokeOpacity: 0.8,
				    strokeWeight: 2,
				    fillColor: '#FF0000',
				    fillOpacity: 0.35,
				    visible:false
				});
				//把对象挂到scope中
				model.assign(scope, rectangle);
	        }
        	
			var bounds = {north: null, south: null, east: null, west: null};
			var mapClickCount = 0;//地图点击事件次数
			//点击1下鼠标时启动选择框，第二次点击时关闭选择框
			var addClickEvent = function(event){
				  	mapClickCount++;
				  	//纬度X轴
				  	if(bounds.north == null){
				  		bounds.north = bounds.south = event.latLng.lat();
				  	}else{
				  		bounds.south = event.latLng.lat();
				  	}
				  	//经度Y轴
				  	if(bounds.west == null){
				  		bounds.west = bounds.east = event.latLng.lng();
				  	}else{
				  		bounds.east = event.latLng.lng();
				  	}
				  	//设置选择框大小
				  	rectangle.setBounds(bounds);
				  	rectangle.setVisible(true);
				  	//结束选择隐藏矩形选择框
				  	if(mapClickCount == 2){
				  		//执行回调函数
				  		if(selectedFun){
				  			selectedFun(bounds);
				  		}		  		
						
						//重置选择框
					  	bounds.north = bounds.south= bounds.east = bounds.west = null;
						rectangle.setVisible(false);
				        mapClickCount = 0;
				  	}
			}
			
			//鼠标移动时改变选择框的大小
			var addMousemoveEvent = function(event){
			 	if(bounds.south != null){
					bounds.south = event.latLng.lat();
					bounds.east = event.latLng.lng();
				 	rectangle.setBounds(bounds);
			  	}
			}
			
			//装饰setMap方法
            var _setMap = rectangle.setMap;
            rectangle.setMap = function open(map) {
            	//移除之前绑定的事件
            	if(this.selectModeClickFun_){
            		this.selectModeClickFun_.remove();
        		}
        		if(this.selectModeChangeFun_){
            		this.selectModeChangeFun_.remove();
        		}
            	if(map){
            		this.selectModeClickFun_ = map.addListener('click', addClickEvent);
					this.selectModeChangeFun_ = map.addListener('mousemove', addMousemoveEvent);
            	}
             	//执行本身的方法
            	_setMap.call(rectangle, map);
            };
			
			rectangle.addListener('click', addClickEvent);			
			rectangle.addListener('mousemove', addMousemoveEvent);
			
			scope.$on('$destroy', function(){
        		if(rectangle != null){
        			rectangle.setMap(null);
        			rectangle = null;
        		}
        	});
        }
      };
  }]);
  
  //TOPO模式指令
  app.directive('uiMapTopoMode', ['$parse', function ($parse) {
      return {
        restrict: 'A',
        link: function (scope, elm, attrs) {
        	var model = $parse(attrs.uiMapTopoMode);
          	var topo = model(scope);
          	// 选择框为null时初始化选择框
          	if (!topo) {
          		topo = {};
				//把对象挂到scope中
				model.assign(scope, topo);
	        }
        	topo.topoLinePaths = [];
        	//清空TOPO
        	topo.clear = function(){
        		 angular.forEach(this.topoLinePaths, function(path, index){
					  path.setMap(null);
			  	 });
				 this.topoLinePaths = [];
        	}
        	//添加Topo
        	topo.addTopo = function(map, marker, subMarkers){
        		var self = this;
        		var gateway = marker.bemsObj
        		angular.forEach(subMarkers, function(mark, index){
				  	var device = mark.bemsObj;
				  	//如果不等于1说明是传感器,把同一网关的传感器连起来
				  	if(device.deviceType !== 1 && device.gatewayId == gateway.gatewayId){
				  		self.topoLinePaths.push(
				  			new google.maps.Polyline({
							    path: [
							    	{lat: marker.getPosition().lat(), lng: marker.getPosition().lng()},
							    	{lat: mark.getPosition().lat(), lng: mark.getPosition().lng()}
							    ],
							    geodesic: true,
							    strokeColor: '#FF0000',
							    strokeOpacity: 1.0,
							    strokeWeight: 2,
							    map: map
						    })
					   );
				  	}
				});
        	}
        	scope.$on('map-topo-clear', function(){
        		topo.clear();
        	});
        	scope.$on('$destroy', function(){
        		topo.clear();
        	});
        }
      };
  }]);
    
  //自定义信息窗口,自还的信息窗口无法满足需求
  function difineInfoWindow(){
  	/** @constructor */
	var USGSOverlay = function (dom) {
	  // actually create this div upon receipt of the onAdd()
	  // method so we'll leave it null for now.
	  this.div_ = dom;
	}
	USGSOverlay.prototype = new window.google.maps.OverlayView();
	
	/**
	 * onAdd is called when the map's panes are ready and the overlay has been
	 * added to the map.
	 */
	USGSOverlay.prototype.onAdd = function() {
	  // Add the element to the "overlayImage" pane.
	  var panes = this.getPanes();
	  panes.floatPane.appendChild(this.div_);
	};
	
	USGSOverlay.prototype.draw = function() {
	
	  // We use the south-west and north-east
	  // coordinates of the overlay to peg it to the correct position and size.
	  // To do this, we need to retrieve the projection from the overlay.
	  var overlayProjection = this.getProjection();
	
	  // We'll use these coordinates to resize the div.
	  var position = this.marker_.getPosition();
	  var pixel = overlayProjection.fromLatLngToDivPixel(position);
	
	  // Resize the image's div to fit the indicated dimensions.
	  var div = this.div_;
	  var x = (pixel.x - (div.clientWidth/2));
	  var y = (pixel.y - div.clientHeight - 20);
	  div.style.left = x + 'px';
	  div.style.top = y + 'px';
	  div.style.position = 'absolute';
	  /*if(this.map){
		  var latLng = overlayProjection.fromDivPixelToLatLng(new google.maps.Point(x, y));
		  var extent = this.map.getBounds();
		  if(extent == null){
			return null;
		  }
		  var topLeftLatitude = extent.getNorthEast().lat();
		  //InfoWindow太高无法显示全部时,设定一下位置让地图移动使InfoWindow显示出来
		  if(latLng.lat() > topLeftLatitude){
		  	this.map.panBy(null, y);
		  }
		  latLng.lng();
	  }*/
	};
	
	USGSOverlay.prototype.onRemove = function() {
	  this.div_.parentNode.removeChild(this.div_);
	};
	
	// Set the visibility to 'hidden' or 'visible'.
	USGSOverlay.prototype.close = function() {
	  if (this.div_) {
	    // The visibility property must be a string enclosed in quotes.
	    this.div_.style.display = 'none';
	  }
	};
	
	USGSOverlay.prototype.open = function(map, marker) {
	  // Explicitly call setMap on this overlay
	  this.setMap(map);
	  this.marker_ = marker;
	  if (this.div_) {
	    this.div_.style.display = 'block';
	  }
	};
	window.USGSOverlay = USGSOverlay;
  }
  
})();
